package com.bicon.botu.file.upload.common;

import com.bicon.botu.core.base.common.entity.BaseResult;
import com.bicon.botu.file.upload.vo.AudioProcess;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.MultimediaInfo;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.springframework.beans.factory.annotation.Value;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

/**
 * 音频转码
 *
 * @author 李双喜
 * @date 2018/2/24 9:47
 */
public class CoverAudio {
    @Value("${server.path}")
    String serverPath;
    @Value("${disk.path}")
    String diskPath;
    private String PATH;

    public CoverAudio(String path) {
        PATH = path;
    }

    public BaseResult<AudioProcess> beginCover(File file, String audioFilePath) {
        AudioProcess audioProcess = new AudioProcess();
        if (!checkfile(PATH)) {
            return new BaseResult(404, "系统文件找不到");
        }
        int i = 2;
        int j = 0;
        if (checkContentType() == i) {
            //当音频为MP3，只需要将时长和大小返回即可
            audioProcess.setAudioSize(this.ReadAudioSize(file));
            String timeTwo = this.audioTimeTwo(audioFilePath + ".mp3");
            if (!"0".equals(timeTwo)) {
                audioProcess.setAudioTime(timeTwo);
            }else {
                audioProcess.setAudioTime(this.audioTime(file));
            }
            audioProcess.setAudioCoverPath(audioFilePath + "." + "mp3");
            return new BaseResult(200, "success", audioProcess);
        } else if (checkContentType() == j) {
            //当音频为可转换的格式时，需要先进行转换成MP3
            AudioProcess audioDTO = this.processMP3(PATH, audioFilePath);
            return new BaseResult(200, "success", audioDTO);
        } else {
            return new BaseResult(600, "此格式不支持转换");
        }
    }












    /**
     * 判断文件是否是文件
     */
    private boolean checkfile(String path) {
        File file = new File(path);
        if (file.isFile()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查音频类型能否被ffmpeg转码
     *
     * @return
     */
    private int checkContentType() {
        String type = PATH.substring(PATH.lastIndexOf(".") + 1, PATH.length())
                .toLowerCase();

        // ffmpeg能解析的格式：（wav,amr,mp3等）
        if (type.equals("mp3")) {
            return 2;
        } else if (type.equals("wav")) {
            return 0;
        } else if (type.equals("amr")) {
            return 0;
        } else {
            return 9;
        }
    }

    /**
     * 获取音频时长(经测试有些MP3文件无时长)
     */
    private String audioTime(File file) {
        try {
            MP3File f = (MP3File) AudioFileIO.read(file);
            MP3AudioHeader audioHeader = (MP3AudioHeader) f.getAudioHeader();
            return audioHeader.getTrackLength() + "";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0 + "";
    }


    public String audioTimeTwo (String audioPath) {
        File source = new File(audioPath);
        Encoder encoder = new Encoder();
        try {
            MultimediaInfo m = encoder.getInfo(source);
            Long ls = m.getDuration()/1000;
            //BigDecimal time = new BigDecimal(ls.toString()).setScale(0, BigDecimal.ROUND_HALF_UP);(四舍五入)
            return ls.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0+"";
    }

    /**
     * 获取音频大小
     *
     * @param source
     * @return
     */
    private String ReadAudioSize(File source) {
        FileChannel fc = null;
        String size = "";
        try {
            @SuppressWarnings("resource")
            FileInputStream fis = new FileInputStream(source);
            fc = fis.getChannel();
            BigDecimal fileSize = new BigDecimal(fc.size());
            size = fileSize.divide(new BigDecimal(1048576), 2, RoundingMode.HALF_UP) + "MB";
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != fc) {
                try {
                    fc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return size;
    }

    /**
     * 转换Mp3
     */
    private AudioProcess processMP3(String oldFilePath, String audioFilePath) {
        AudioProcess audioProcess = new AudioProcess();
        List commend = new ArrayList();
        commend.add("/usr/local/ffmpeg/ffmpeg/install/dir/bin/ffmpeg");
        commend.add("-i");
        commend.add(oldFilePath);
        commend.add("-f");
        commend.add("mp3");
        commend.add("-acodec");
        commend.add("libmp3lame");
        commend.add("-y");
        commend.add(audioFilePath + ".mp3");
        Process process = null;
        try {
            String commendString = commend.toString().replace(",", " ");
            StringBuffer stringBuffer = new StringBuffer(commendString);
            StringBuffer buf = stringBuffer.deleteCharAt(0).deleteCharAt(stringBuffer.length() - 1);
            process = Runtime.getRuntime().exec(buf.toString());
            StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");
            errorGobbler.start();//  kick  off  stderr
            StreamGobbler outGobbler = new StreamGobbler(process.getInputStream(), "STDOUT");
            outGobbler.start();//  kick  off  stdout
            process.waitFor();
            audioProcess.setAudioTime(this.audioTimeTwo(audioFilePath + ".mp3"));
            //audioProcess.setAudioTime(this.audioTime(new File(audioFilePath + ".mp3")));(此方法部分时长获取不到)
            boolean delete = deleteVideoFile(oldFilePath);
            if (delete) {
                audioProcess.setAudioCoverPath(audioFilePath + ".mp3");
                audioProcess.setAudioSize(this.ReadAudioSize(new File(audioFilePath + ".mp3")));
                audioProcess.setAudioTime(this.audioTimeTwo(audioFilePath + ".mp3"));
                //audioProcess.setAudioTime(this.audioTime(new File(audioFilePath + ".mp3")));(此方法获取时长部分为0)
                return audioProcess;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public int doWaitFor(Process p) {
        InputStream in = null;
        InputStream err = null;
        int exitValue = -1;
        try {
            in = p.getInputStream();
            err = p.getErrorStream();
            boolean finished = false;
            while (!finished) {
                try {
                    while (in.available() > 0) {
                        Character c = new Character((char) in.read());
                    }
                    while (err.available() > 0) {
                        Character c = new Character((char) err.read());
                    }
                    exitValue = p.exitValue();
                    finished = true;

                } catch (IllegalThreadStateException e) {
                    Thread.currentThread().sleep(500);
                }
            }
        } catch (Exception e) {
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
            }
            if (err != null) {
                try {
                    err.close();
                } catch (IOException e) {
                }
            }
        }
        return exitValue;
    }


    /**
     * 删除音频文件
     *
     * @param filepath
     */
    public boolean deleteVideoFile(String filepath) {
        File file = new File(filepath);
        if (PATH.equals(filepath)) {
            if (file.delete()) {
                return true;
            }
        } else {
            if (file.delete()) {
                return true;
            }
            File filedelete2 = new File(PATH);
            if (filedelete2.delete()) {
                return true;
            }
        }
        return false;
    }
}

